package com.bringspring.extend.service.impl;

import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bringspring.common.base.UserInfo;
import com.bringspring.common.base.vo.DownloadVO;
import com.bringspring.common.config.ConfigValueUtil;
import com.bringspring.common.config.constant.ConfigConst;
import com.bringspring.common.util.*;
import com.bringspring.extend.entity.DocumentEntity;
import com.bringspring.extend.entity.DocumentHistoryEntity;
import com.bringspring.extend.entity.DocumentShareEntity;
import com.bringspring.extend.mapper.DocumentMapper;
import com.bringspring.extend.model.document.DocumentShareForm;
import com.bringspring.extend.model.document.PageDocument;
import com.bringspring.extend.service.DocumentHistoryService;
import com.bringspring.extend.service.DocumentService;
import com.bringspring.extend.service.DocumentShareService;
import com.bringspring.extend.utils.CommonUtil;
import com.bringspring.extend.utils.DictionaryConversion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 知识文档
 *
 * @author 开发平台组
 * @copyright 股份有限公司
 * @date 2017年9月26日 上午9:18
 */
@Service
public class DocumentServiceImpl extends ServiceImpl<DocumentMapper, DocumentEntity> implements DocumentService {

    @Autowired
    private UserProvider userProvider;
    @Autowired
    private DocumentShareService documentShareService;
    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private DocumentHistoryService documentHistoryService;
    @Autowired
    private DictionaryConversion dictionaryConversion;

    public static String temporaryZip="temporaryZip"+File.separator;
    @Override
    public List<DocumentEntity> getFolderList() {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, userProvider.get().getUserId())
                .eq(DocumentEntity::getType, 0)
                .eq(DocumentEntity::getDeleteMark, 0)
                .orderByAsc(DocumentEntity::getCreatorTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getAllList(String parentId, String isPublic) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getIsPublic, isPublic)
                .eq(DocumentEntity::getDeleteMark, 0)
                .eq(DocumentEntity::getParentId, parentId)
                .orderByAsc(DocumentEntity::getType)
                .orderByAsc(DocumentEntity::getCreatorTime);
        if ("1".equals(isPublic)) {
            queryWrapper.lambda().eq(DocumentEntity::getCreatorUserId, userProvider.get().getUserId());
        }
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getAllList(PageDocument page) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getDeleteMark, 0)
                .eq(DocumentEntity::getParentId, page.getParentId())
                .orderByAsc(DocumentEntity::getType)
                .orderByAsc(DocumentEntity::getCreatorTime)
                .eq(DocumentEntity::getIsPublic, page.getIsPublic());
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getTrashList() {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, userProvider.get().getUserId())
                .eq(DocumentEntity::getDeleteMark, 1)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getDeleteTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getShareOutList() {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(DocumentEntity::getCreatorUserId, userProvider.get().getUserId())
                .eq(DocumentEntity::getDeleteMark, 0)
                .gt(DocumentEntity::getIsShare, 0)
                .orderByAsc(DocumentEntity::getType)
                .orderByDesc(DocumentEntity::getDeleteTime);
        return this.list(queryWrapper);
    }

    @Override
    public List<DocumentEntity> getShareTomeList() {
        return this.baseMapper.getShareTomeList(userProvider.get().getUserId());
    }

    @Override
    public List<DocumentShareEntity> getShareUserList(String documentId) {
        QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentId);
        return documentShareService.list(queryWrapper);
    }

    @Override
    public DocumentEntity getInfo(String id) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getId, id);
        return this.getOne(queryWrapper);
    }

    @Override
    public void delete(DocumentEntity entity) {
        entity.setDeleteTime(new Date());
        entity.setDeleteUserId(userProvider.get().getUserId());
        entity.setDeleteMark(1);
        this.updateById(entity);
    }

    @Override
    public void create(DocumentEntity entity) {
        entity.setCreatorUserId(userProvider.get().getUserId());
        entity.setDeleteMark(0);
        this.save(entity);
    }

    @Override
    public boolean update(String id, DocumentEntity entity) {
        entity.setId(id);
        entity.setLastModifyTime(new Date());
        entity.setLastModifyUserId(userProvider.get().getUserId());
        return this.updateById(entity);
    }

    @Override
    @DSTransactional
    public boolean shareCreate(String documentId, DocumentShareForm documentShareForm) {
        List<DocumentShareEntity> entitys = new ArrayList<>();
        if (documentShareForm.getShareType().equals("1")) {
            String[] shareUserId = documentShareForm.getUserId().split(",");
            for (String item : shareUserId) {
                DocumentShareEntity entity = JsonUtil.getJsonToBean(documentShareForm, DocumentShareEntity.class);
                String uuId = RandomUtil.uuId();
                entity.setDocumentId(documentId);
                entity.setId(uuId);
                entity.setShareUserId(item);
                entity.setExposeLink(documentShareForm.getExposeLink() + "?id=" + uuId);
                entitys.add(entity);
            }
        } else {
            DocumentShareEntity entity = JsonUtil.getJsonToBean(documentShareForm, DocumentShareEntity.class);
            String uuId = RandomUtil.uuId();
            entity.setDocumentId(documentId);
            entity.setId(uuId);
            entity.setExposeLink(documentShareForm.getExposeLink() + "?id=" + uuId);
            entitys.add(entity);
        }

        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        DocumentEntity entity = this.getOne(queryWrapper.lambda().eq(DocumentEntity::getId, documentId));
        if (entity != null) {
            entity.setIsShare(entitys.size());
            entity.setShareTime(new Date());
            this.updateById(entity);
            if (documentShareForm.getShareType().equals("1")) {
                QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
                wrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentId).eq(DocumentShareEntity::getShareType, "1");
                documentShareService.remove(wrapper);
            }
            documentShareService.saveBatch(entitys);

            return true;
        }
        return false;
    }

    @Override
    public boolean shareUpdate(String shareId, DocumentShareForm documentShareForm) {
        DocumentShareForm shareEntityById = this.getShareEntityById(shareId);
        if (shareEntityById != null) {
            if (documentShareForm.getShareType().equals("1")) {
                String[] shareUserId = documentShareForm.getUserId().split(",");
                List<DocumentShareEntity> entitys = new ArrayList<>();
                for (String s : shareUserId) {
                    DocumentShareEntity documentShareEntity = JsonUtil.getJsonToBean(documentShareForm, DocumentShareEntity.class);
                    documentShareEntity.setShareUserId(s);
                    String uuId = RandomUtil.uuId();
                    documentShareEntity.setId(uuId);
                    String str = org.apache.commons.lang3.StringUtils.substringBefore(documentShareEntity.getExposeLink(), "id");
                    documentShareEntity.setExposeLink(str + "id=" + uuId);
                    entitys.add(documentShareEntity);
                }
                QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
                wrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentShareForm.getDocumentId()).eq(DocumentShareEntity::getShareType, "1");
                documentShareService.remove(wrapper);
                documentShareService.saveBatch(entitys);
            } else {
                DocumentShareEntity documentShareEntity = JsonUtil.getJsonToBean(documentShareForm, DocumentShareEntity.class);
                if ("2".equals(documentShareForm.getPassword())) {
                    documentShareEntity.setPassword(CommonUtil.RandomGenerator());
                }
                documentShareService.updateById(documentShareEntity);
            }
            return true;
        }
        return false;
    }

    @Override
    public DocumentShareForm getShareEntityById(String shareId) {
        QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(DocumentShareEntity::getId, shareId);
        DocumentShareEntity one = documentShareService.getOne(wrapper);
        DocumentShareForm documentShareForm = JsonUtil.getJsonToBean(one, DocumentShareForm.class);
        if (one.getShareType().equals("1")) {
            QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(DocumentShareEntity::getDocumentId, one.getDocumentId()).eq(DocumentShareEntity::getShareType, "1");
            List<DocumentShareEntity> list = documentShareService.list(queryWrapper);
            List<String> collect = list.stream().map(DocumentShareEntity::getShareUserId).collect(Collectors.toList());
            List<String> userNameList = new ArrayList<>();
            for (String s : collect) {
                userNameList.add(dictionaryConversion.userSelectValues(s));
            }
            documentShareForm.setCreatorUserName(dictionaryConversion.userSelectValues(documentShareForm.getCreatorUserId()));
            documentShareForm.setShareUserName(String.join(",", userNameList));
        }
        return documentShareForm;
    }

    @Override
    @DSTransactional
    public boolean shareCancel(String documentId) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getId, documentId);
        DocumentEntity entity = this.getOne(queryWrapper);
        if (entity != null) {
            entity.setIsShare(0);
            entity.setShareTime(new Date());
            this.updateById(entity);
            QueryWrapper<DocumentShareEntity> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(DocumentShareEntity::getDocumentId, documentId);
            documentShareService.remove(wrapper);
            return true;
        }
        return false;
    }

    @Override
    public boolean handleDelShareLink(String id) {
        DocumentShareForm shareEntityById = this.getShareEntityById(id);
        if (shareEntityById != null) {
            if (shareEntityById.getShareType().equals("1")) {
                QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
                queryWrapper.lambda().eq(DocumentShareEntity::getDocumentId, shareEntityById.getDocumentId()).eq(DocumentShareEntity::getShareType, "1");
                List<DocumentShareEntity> list = documentShareService.list(queryWrapper);
                documentShareService.removeBatchByIds(list);
            } else {
                documentShareService.removeById(id);
            }
            QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(DocumentShareEntity::getDocumentId, shareEntityById.getDocumentId());
            List<DocumentShareEntity> list = documentShareService.list(queryWrapper);
            if (list.isEmpty()) {
                DocumentEntity entity = this.getInfo(shareEntityById.getDocumentId());
                if (entity != null) {
                    entity.setIsShare(0);
                    entity.setShareTime(new Date());
                    this.updateById(entity);
                }
            }

            return true;
        }

        return false;
    }

    @Override
    @DSTransactional
    public void trashDelete(String folderId) {
        DocumentEntity entity = this.getInfo(folderId);
        if (entity != null) {
            this.removeById(folderId);
            FileUtil.deleteFile(configValueUtil.getDocumentFilePath() + entity.getFilePath());
            List<DocumentHistoryEntity> listByOriginalFileId = documentHistoryService.getListByOriginalFileId(entity.getId());
            if (!listByOriginalFileId.isEmpty()) {
                documentHistoryService.removeBatchByIds(listByOriginalFileId);
            }
        }
//        List<DocumentEntity> list = this.baseMapper.GetChildList(folderId);
//        List<String> deleteId = new ArrayList<>();
//        for (DocumentEntity entity : list) {
//            if(!StringUtil.isEmpty(entity.getFilePath())){
//                FileUtil.deleteFile(configValueUtil.getDocumentFilePath() + entity.getFilePath());
//            }
//            deleteId.add(entity.getId());
//        }
//        this.removeByIds(deleteId);
    }

    @Override
    public boolean trashRecovery(String id) {

//        return retBool(this.baseMapper.trashRecovery(id));
        DocumentEntity info = this.getInfo(id);
        if (info != null) {
            info.setEnabledMark(0);
            info.setDeleteMark(0);
            this.updateById(info);
            return true;
        }
        return false;
    }

    @Override
    public boolean moveTo(String id, String toId) {
        DocumentEntity entity = this.getInfo(id);
        if (entity != null) {
            entity.setParentId(toId);
            this.updateById(entity);
            return true;
        }
        return false;
    }

    @Override
    public boolean isExistByFullName(DocumentEntity entity) {
        String userId = userProvider.get().getUserId();
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getFullName, entity.getFullName()).eq(DocumentEntity::getDeleteMark, 0).eq(DocumentEntity::getCreatorUserId, userId).eq(DocumentEntity::getFilePath, entity.getFilePath());
        if (!StringUtils.isEmpty(entity.getId())) {
            queryWrapper.lambda().ne(DocumentEntity::getId, entity.getId());
        }
        return this.count(queryWrapper) > 0 ? true : false;
    }

    @Override
    public List<DocumentEntity> getListByShareUserId() {
        UserInfo userInfo = userProvider.get();
        QueryWrapper<DocumentShareEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentShareEntity::getShareUserId, userInfo.getUserId());

        List<DocumentShareEntity> list = documentShareService.list(queryWrapper);
        List<DocumentEntity> documentEntities = new ArrayList<>();

        if (!list.isEmpty()) {
            for (DocumentShareEntity documentShareEntity : list) {
                DocumentEntity info = this.getInfo(documentShareEntity.getDocumentId());
                if (ObjectUtils.isNotEmpty(info)) {
                    documentEntities.add(info);
                }
            }
        }
        return documentEntities;
    }



    @Override
    public DownloadVO getAllDocumentByParentId(String id) {
        List<DocumentEntity> list = new ArrayList<>();
        DocumentEntity info = this.getInfo(id);
        UserInfo userInfo = userProvider.get();
        this.getAllChildrenDoc(list,id);
        String fromPath=configValueUtil.getDocumentFilePath();
        String toPath=configValueUtil.getDocumentFilePath()+temporaryZip;

        for (DocumentEntity documentEntity : list) {

            boolean b = FileUtil.copyFile(fromPath + documentEntity.getFilePath(), (toPath + documentEntity.getFilePath()).substring(0, (toPath + documentEntity.getFilePath()).lastIndexOf(File.separator)+1), documentEntity.getFullName());
            if (!b) {
                return new DownloadVO();
            }
        }
        String zipName = info.getFullName();
        String outPath=toPath+info.getFilePath();
        String zipPath=toPath+zipName+".zip";
        if (new File(zipPath).exists()) {
            new File(zipPath).delete();
        }
        FileUtil.toZip(zipPath,true,outPath+File.separator);
        String fileName = userInfo.getId() + "#" + zipName+".zip" + "#documentZip#"+ zipName+".zip" + ".zip" ;
        DownloadVO vo = DownloadVO.builder().name(zipName+".zip").url(UploaderUtil.uploaderFile(fileName)).build();
        return vo;
    }

    @Override
    public String getAbsoluteRouteById(String id) {
        UserInfo userInfo = userProvider.get();
        String path = configValueUtil.getDocumentFilePath();
        List<String> pathList = new ArrayList<>();
        this.getParentPath(pathList, id);
        Collections.reverse(pathList);
        String collect = pathList.stream().collect(Collectors.joining(File.separator));
        path +=userInfo.getUserId()+File.separator+ DateUtil.getNowYear() + File.separator+collect+File.separator;
        return path;
    }

    @Override
    public void clearDoc() {
        String path = configValueUtil.getDocumentFilePath() + ConfigConst.DOCUMENT_ZIP;
        this.deleteFileByIO(path);
    }

    /**
     * 通过递归逐层删除文件信息
     *
     * @param filePath
     */
    public static void deleteFileByIO(String filePath) {
        File file = new File(filePath);
        File[] list = file.listFiles();
        if (list != null) {
            for (File temp : list) {
                deleteFileByIO(temp.getAbsolutePath());
            }
        }
        file.delete();
    }



    public void getParentPath(List<String> pathList, String id) {
        DocumentEntity info = this.getInfo(id);
        if (info != null) {
            pathList.add(info.getFullName());
            if (!"0".equals(info.getParentId())) {
                getParentPath(pathList, info.getParentId());
            }
        }
    }

    /**
     * 根据文件id获取数据库 当前文件夹下的所有文件
     * @param
     * @return
     */
    public void getAllChildrenDoc(List<DocumentEntity> childrenList, String parentId) {
        QueryWrapper<DocumentEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(DocumentEntity::getParentId, parentId);
        List<DocumentEntity> list = this.list(queryWrapper);
        if (!list.isEmpty()) {
            for (DocumentEntity documentEntity : list) {
                if (documentEntity.getType()==0) {
                    getAllChildrenDoc(childrenList,documentEntity.getId());
                }else {
                    childrenList.add(documentEntity);
                }
            }

        }
    }

    /**
     * 根据文件id获取磁盘当前文件夹下的所有文件
     * @param id
     * @return
     */
    public List<File> getAllDocByAbsoluteRoute(String id){
        DocumentEntity info = this.getInfo(id);
        String basePath=configValueUtil.getDocumentFilePath()+info.getFilePath();
        //将该目录下的所有文件复制到一个临时目录
        String path = configValueUtil.getDocumentFilePath()+temporaryZip+userProvider.get().getUserId()+File.separator+ info.getFullName()+File.separator;
        FileUtil.copy(basePath,path);
        File dir = new File(path);
        List<File> allFileList = new ArrayList<>();
        // 判断文件夹是否存在
        if (!dir.exists()) {
            System.out.println("目录不存在");
            return allFileList;
        }
        getAllFile(dir, allFileList);
        return allFileList;
    }
    /**
     * 获取文件列表
     * @param fileInput
     * @param allFileList
     */
    public static void getAllFile(File fileInput, List<File> allFileList) {
        // 获取文件列表
        File[] fileList = fileInput.listFiles();
        assert fileList != null;
        for (File file : fileList) {
            if (file.isDirectory()) {
                // 递归处理文件夹
                // 如果不想统计子文件夹则可以将下一行注释掉
                getAllFile(file, allFileList);
            } else {
                // 如果是文件则将其加入到文件数组中
                allFileList.add(file);
            }
        }
    }

}

